package com.websocket.handler;

import java.io.IOException;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.BinaryMessage;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.PongMessage;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;

import com.system.comm.utils.FrameJsonUtil;
import com.system.comm.utils.FrameMapUtil;
import com.system.comm.utils.FrameSpringBeanUtil;
import com.system.comm.utils.FrameStringUtil;
import com.system.handle.model.ResponseFrame;
import com.websocket.data.WebSocketData;
import com.websocket.pojo.User;

@Component
public class WebSocketMsgHandler extends AbstractWebSocketHandler {
	
	private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketMsgHandler.class);

	private WebSocketData webSocketData = null;
	private WebSocketData getWebSocketData() {
		if (webSocketData == null) {
			webSocketData = FrameSpringBeanUtil.getBean(WebSocketData.class);
		}
    	return webSocketData;
	}
	
    /**
     * 存储sessionId和webSocketSession
     * 需要注意的是，webSocketSession没有提供无参构造，不能进行序列化，也就不能通过redis存储
     * 在分布式系统中，要想别的办法实现webSocketSession共享
     */
    //private static Map<String, WebSocketSession> sessionMap = new ConcurrentHashMap<>();
    //private static Map<String, String> tokenMap = new ConcurrentHashMap<>();

    /**
     * webSocket连接创建后调用
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) {
        // 获取参数
        String token = String.valueOf(session.getAttributes().get("token"));
        getWebSocketData().addUser(token, session);
        //tokenMap.put(token, getSessionId(session));
        //sessionMap.put(sessionId, session);
        LOGGER.info("{}-webSocket连接创建成功!", token);
    }

    /**
     * 接收到消息会调用
     */
    @Override
    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
        if (message instanceof TextMessage) {
        	String text = message.getPayload().toString();
        	Map<String, Object> data = FrameJsonUtil.toMap(text);
        	if (data != null) {
        		String type = FrameMapUtil.getString(data, "type");
        		if ("subscribe".equals(type)) {
        			// 订阅
        			getWebSocketData().subscribe(session, data);
        		} else {
        			getWebSocketData().other(session, data);
        		}
        	}
        } else if (message instanceof BinaryMessage) {

        } else if (message instanceof PongMessage) {

        } else {
            LOGGER.error("Unexpected WebSocket message type:{}", message);
        }
        LOGGER.info("接受信息为:{}", message);
    }

    /**
     * 连接出错会调用
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) {
        //sessionMap.remove(getSessionId(session));
    	getWebSocketData().removeUser(session);
    }

    /**
     * 连接关闭会调用
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
        //sessionMap.remove(getSessionId(session));
    	getWebSocketData().removeUser(session);
    }

    @Override
    public boolean supportsPartialMessages() {
        return false;
    }

    /**
     * 后端发送消息
     */
    public ResponseFrame sendMessage(String sessionId, String message) {
    	ResponseFrame frame = new ResponseFrame();
        if (FrameStringUtil.isEmpty(sessionId)) {
        	frame.setCode(-2);
        	frame.setMessage("不存在接收用户");
        	return frame;
        }
        User user = getWebSocketData().getUser(sessionId);
        WebSocketSession session = user.getWebSocketSession();
        try {
            session.sendMessage(new TextMessage(message));
            frame.setSucc();
        } catch (IOException e) {
            LOGGER.error(e.getMessage(), e);
            frame.setCode(-2);
            frame.setMessage(e.getMessage());
        }
        return frame;
    }
}